/*
 * "Hello World" example.
 *
 * This example prints 'Hello from Nios II' to the STDOUT stream. It runs on
 * the Nios II 'standard', 'full_featured', 'fast', and 'low_cost' example
 * designs. It runs with or without the MicroC/OS-II RTOS and requires a STDOUT
 * device in your system's hardware.
 * The memory footprint of this hosted application is ~69 kbytes by default
 * using the standard reference design.
 *
 * For a reduced footprint version of this template, and an explanation of how
 * to reduce the memory footprint for a given application, see the
 * "small_hello_world" template.
 *
 */

#include <stdio.h>
#include "system.h"

#include "altera_avalon_uart.h"
#include "sys/alt_dev.h"
#include <stdlib.h> // malloc, free
#include <string.h>
#include <stddef.h>
#include <unistd.h>  // usleep (unix standard?)
#include <fcntl.h>
#include "altera_avalon_pio_regs.h"


#include"LCD_1602_4wire.h"

#include <stdio.h>
#include "define.h"
#include <system.h>
#include <alt_types.h>
#include "socket.h"
#include "w5100_nios2.h"
#include "types.h"
#include <unistd.h>
#include <string.h>
#include <io.h>

//#include <sys/alt_timestamp.h>
#define TCP_PORT         80       // TCP/IP Port
#define MAX_BUFFER_SIZE 1024


void test_lcd()
{
	//InitLcd();
	PutStr("Hello",1,1);

}

/*void my_sleep(alt_u32 usec)
{
  alt_u32 span = (alt_timestamp_freq() / 1000000) * usec;
  alt_u32 end = alt_timestamp() + span;

  while(alt_timestamp() < end);
}*/

// todo: replace with sscanf or something better? this is undocumented
alt_u16 strindex(alt_u8* s, alt_u8* t)
{
  alt_u16 i,n;

  n=strlen(t);
  for(i=0;*(s+i); i++) {
    if (strncmp(s+i,t,n) == 0)
      return i;
  }
  return -1;
}

int test_eth()
{
	static SOCKET sock = 0;
	alt_u8 socket_status = 0;
	alt_u16 receive_request_size = 0;
	alt_u16 bytes_received = 0;
	static alt_u8 rx_buffer[MAX_BUFFER_SIZE];
	static alt_u8 tx_buffer[MAX_BUFFER_SIZE];
	alt_8 getidx = 0;
	alt_8 postidx = 0;

	alt_u8 radiostat0[10], radiostat1[10], temp[4];
	alt_u8 led_state = 1;
	alt_u8 tempvalue = 25;
	alt_8 result = 0;

	// clear the buffer memories
	memset( rx_buffer, 0, MAX_BUFFER_SIZE );
	memset( tx_buffer, 0, MAX_BUFFER_SIZE );
	memset( radiostat0, 0, 10 );
	memset( radiostat1, 0, 10 );
	memset( temp, 0, 4 );

	// Set LED to 0.3Hz, 10%ish duty
	IOWR ( PIO_0_BASE, DIRECTION, 0xFF );   // write direction, ALL OUT
	IOWR ( PIO_0_BASE, DATA, 0xFE ); 		// 7:4 - SPEED, 3:0 - DUTY

	wiz_init(); // init the w5100 ethernet chip
	sysinit( 0, 0 ); // this allocates the size of tx & rx buffers for each socket/ch
					// 0 gives 1k rx/ 1k tx to each of the 4 sockets
	// http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
	// open a UDP socket
//	socket( sock, Sn_MR_UDP, 0x0007, 0 );
//	printf("\nSocket 0 - UDP: open");

	printf( "\r\nmain(): --- Web server example! ---\r\n\r\n" );

	while (1)
	{
		// what's the socket doing?
		socket_status = wiz( READ, Sn_SR( sock ) );

		switch ( socket_status )
		{
			case SOCK_CLOSED:
			{
				// open a new socket
				if ( socket( sock, Sn_MR_TCP, TCP_PORT, 0 ) == 1 )
				{
					// listen for tcp connection
					if ( listen( sock ) == 0 )
					{
						printf(".");
						usleep( 1000 );
					}
					else
					{
						printf("SOCKET_CLOSED: Socket Listen!\n");
					}
				}
				else
				{
					printf("SOCKET_CLOSED: FAIL - can't open a socket\n");
				}
				break;
			}

			case SOCK_ESTABLISHED:
			{
				// how many bytes are we fishing out of the w5100?
				receive_request_size = wiz( READ, Sn_RX_RSR0(sock) );
				receive_request_size = ( receive_request_size << 8 ) & 0xFF00;
				receive_request_size += wiz( READ, Sn_RX_RSR1(sock) );
				// todo: dynamically allocate memory for each request read, fixed buffer size isn't safe

				if ( receive_request_size > 0)
				{
					// start the reception
					memset( rx_buffer, 0, MAX_BUFFER_SIZE );
					bytes_received = recv( sock, &rx_buffer[0], receive_request_size );
					if (  bytes_received == receive_request_size )
					{
						printf( "SOCK_ESTABLISHED: Success, received %d bytes\n", bytes_received);
					}
					else
					{
						printf( "SOCK_ESTABLISHED: FAIL, received %d bytes, of %d expected\n", bytes_received, receive_request_size );
					}
					printf("SOCK_ESTABLISHED: Content:\r\n----\r\n%s\r\n----\r\n",rx_buffer);

					// Look in the header to see if its a POST or GET
					getidx = strindex((char *)rx_buffer, "GET /");
					postidx = strindex((char *)rx_buffer, "POST /");
					if (getidx >= 0 || postidx >= 0)
					{
						printf("SOCK_ESTABLISHED: Req. Check!\r\n");
						// Now check the Radio Button for POST request
						//printf(rx_buffer);
						if (postidx >= 0)
						{
							result = strindex((char *)rx_buffer,"radio=0");

							if ( result >= 0)
							{
								led_state = 0;
								printf("SOCK_ESTABLISHED: radio=0\r\n");
								//IOWR ( PIO_0_BASE, DATA, 0xE3 ); 		// 7:4 - SPEED, 3:0 - DUTY
								InitLcd();
							}
							result = strindex((char *)rx_buffer,"radio=1");
							if ( result >= 0)
							{
								led_state = 1;
								printf("SOCK_ESTABLISHED: radio=1\r\n");
								//IOWR ( PIO_0_BASE, DATA, 0xC3 ); 		// 7:4 - SPEED, 3:0 - DUTY
								InitLcd();
								test_lcd();
							}
						}

						// Prepare the response
						strcpy((char *)tx_buffer,("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
						strcat((char *)tx_buffer,("<html><body><span style=\"color:#0000A0\">\r\n"));
						strcat((char *)tx_buffer,("<h1>Embedded Web Server</h1>\r\n"));
						strcat((char *)tx_buffer,("<h3>Arduino Ethernet Shield Demo for Cubic Board</h3>\r\n"));

						strcat((char *)tx_buffer,("<p><form method=\"POST\">\r\n"));
						// Send the response
						if ( send(sock, tx_buffer, strlen((char *)tx_buffer) ) == 0)
						{
							printf( "SOCK_ESTABLISHED: Error sending HTTP response\r\n");
							break;
						}
						else
						{

							// Create the HTTP Temperature Response
							sprintf((char *)temp,"%d",tempvalue);        // Convert temperature value to string
							strcpy((char *)tx_buffer,("<strong>Temp: <input type=\"text\" size=2 value=\""));
							strcat((char *)tx_buffer,temp);
							strcat((char *)tx_buffer,("\"> <sup>O</sup>C\r\n"));

							strcat((char *)tx_buffer,("<h2><font color=\"geen\">Enjoy the Maker Fair!</font></h2>\r\n"));

/*
							if (led_state == 1)
							{
								strcpy(radiostat0,"");
								strcpy(radiostat1,("checked"));
							}
							else
							{
								strcpy(radiostat0,("checked"));
								strcpy(radiostat1,"");
							}

							// Create the HTTP Radio Button 0 Response
							strcat((char *)tx_buffer, ("<p><input type=\"radio\" name=\"radio\" value=\"0\" "));
							strcat((char *)tx_buffer, (char*) radiostat0);
							strcat((char *)tx_buffer, (">Clear LCD Screen\r\n"));
							strcat((char *)tx_buffer, ("<br><input type=\"radio\" name=\"radio\" value=\"1\" "));
							strcat((char *)tx_buffer, (char*) radiostat1);
							strcat((char *)tx_buffer, (">Say Hello~~\r\n"));
							strcat((char *)tx_buffer, ("</strong><p>\r\n"));
							strcat((char *)tx_buffer, ("<input type=\"submit\">\r\n"));
							strcat((char *)tx_buffer, ("</form></span></body></html>\r\n"));
						*/
							strcat((char *)tx_buffer, ("</span></body></html>\r\n"));
							// Now Send the HTTP Remaining Response
							if ( send(sock, tx_buffer, strlen((char *)tx_buffer) ) == 0)
							{
								printf( "SOCK_ESTABLISHED: Error sending HTTP response\r\n");
								break;
							}
							else
							{
								printf( "SOCK_ESTABLISHED: Response sent successfully!\r\n");
							}
						}
					}
					// Disconnect the socket
					disconnect( sock );
					printf( "SOCK_ESTABLISHED: Disconnecting\r\n");
				}
				else
				{
					usleep(10);    // Wait for request
				}
			}
			break;

			case SOCK_FIN_WAIT:
			case SOCK_CLOSING:
			case SOCK_TIME_WAIT:
			case SOCK_CLOSE_WAIT:
			case SOCK_LAST_ACK:
			//default:
			{
				close( sock );
				printf("OTHER: Socket Close!\n");
			}
			break;
		}
	}

	return 0;
}





#define DDR3_IF_BASE 0x8000000

/******************************************************************
*  Function: MemTestDataBus
*
*  Purpose: Tests that the data bus is connected with no
*           stuck-at's, shorts, or open circuits.
*
******************************************************************/
static int MemTestDataBus(unsigned int address)
{
  unsigned int pattern;
  unsigned int ret_code = 0x0;

  /* Perform a walking 1's test at the given address. */
  for (pattern = 1; pattern != 0; pattern <<= 1)
  {
    /* Write the test pattern. */
    IOWR_32DIRECT(address, 0, pattern);

    /* Read it back (immediately is okay for this test). */
    if (IORD_32DIRECT(address, 0) != pattern)
    {
      ret_code = pattern;
      break;
    }
  }
  return ret_code;
}


/******************************************************************
*  Function: MemTestAddressBus
*
*  Purpose: Tests that the address bus is connected with no
*           stuck-at's, shorts, or open circuits.
*
******************************************************************/
static int MemTestAddressBus(unsigned int memory_base, unsigned int nBytes)
{
  unsigned int address_mask = (nBytes - 1);
  unsigned int offset;
  unsigned int test_offset;

  unsigned int pattern     = 0xAAAAAAAA;
  unsigned int antipattern  = 0x55555555;

  unsigned int ret_code = 0x0;

  /* Write the default pattern at each of the power-of-two offsets. */
  for (offset = sizeof(unsigned int); (offset & address_mask) != 0; offset <<= 1)
  {
    IOWR_32DIRECT(memory_base, offset, pattern);
  }

  /* Check for address bits stuck high. */
  test_offset = 0;
  IOWR_32DIRECT(memory_base, test_offset, antipattern);
  for (offset = sizeof(unsigned int); (offset & address_mask) != 0; offset <<= 1)
  {
     if (IORD_32DIRECT(memory_base, offset) != pattern)
     {
        ret_code = (memory_base+offset);
        break;
     }
  }

  /* Check for address bits stuck low or shorted. */
  IOWR_32DIRECT(memory_base, test_offset, pattern);
  for (test_offset = sizeof(unsigned int); (test_offset & address_mask) != 0; test_offset <<= 1)
  {
    if (!ret_code)
    {
      IOWR_32DIRECT(memory_base, test_offset, antipattern);
      for (offset = sizeof(unsigned int); (offset & address_mask) != 0; offset <<= 1)
      {
        if ((IORD_32DIRECT(memory_base, offset) != pattern) && (offset != test_offset))
        {
          ret_code = (memory_base + test_offset);
          break;
        }
      }
      IOWR_32DIRECT(memory_base, test_offset, pattern);
    }
  }

  return ret_code;
}


/******************************************************************
*  Function: MemTest8_16BitAccess
*
*  Purpose: Tests that the memory at the specified base address
*           can be read and written in both byte and half-word
*           modes.
*
******************************************************************/
static int MemTest8_16BitAccess(unsigned int memory_base)
{
  int ret_code = 0x0;

  /* Write 4 bytes */
  IOWR_8DIRECT(memory_base, 0, 0x0A);
  IOWR_8DIRECT(memory_base, 1, 0x05);
  IOWR_8DIRECT(memory_base, 2, 0xA0);
  IOWR_8DIRECT(memory_base, 3, 0x50);

  /* Read it back as one word */
  if(IORD_32DIRECT(memory_base, 0) != 0x50A0050A)
  {
    ret_code = memory_base;
  }

  /* Read it back as two half-words */
  if (!ret_code)
  {
    if ((IORD_16DIRECT(memory_base, 2) != 0x50A0) ||
        (IORD_16DIRECT(memory_base, 0) != 0x050A))
    {
      ret_code = memory_base;
    }
  }

  /* Read it back as 4 bytes */
  if (!ret_code)
  {
    if ((IORD_8DIRECT(memory_base, 3) != 0x50) ||
        (IORD_8DIRECT(memory_base, 2) != 0xA0) ||
        (IORD_8DIRECT(memory_base, 1) != 0x05) ||
        (IORD_8DIRECT(memory_base, 0) != 0x0A))
    {
    ret_code = memory_base;
    }
  }

  /* Write 2 half-words */
  if (!ret_code)
  {
    IOWR_16DIRECT(memory_base, 0, 0x50A0);
    IOWR_16DIRECT(memory_base, 2, 0x050A);

    /* Read it back as one word */
    if(IORD_32DIRECT(memory_base, 0) != 0x050A50A0)
    {
      ret_code = memory_base;
    }
  }

  /* Read it back as two half-words */
  if (!ret_code)
  {
    if ((IORD_16DIRECT(memory_base, 2) != 0x050A) ||
        (IORD_16DIRECT(memory_base, 0) != 0x50A0))
    {
      ret_code = memory_base;
    }
  }

  /* Read it back as 4 bytes */
  if (!ret_code)
  {
    if ((IORD_8DIRECT(memory_base, 3) != 0x05) ||
        (IORD_8DIRECT(memory_base, 2) != 0x0A) ||
        (IORD_8DIRECT(memory_base, 1) != 0x50) ||
        (IORD_8DIRECT(memory_base, 0) != 0xA0))
    {
      ret_code = memory_base;
    }
  }

  return(ret_code);
}


/******************************************************************
*  Function: MemTestDevice
*
*  Purpose: Tests that every bit in the memory device within the
*           specified address range can store both a '1' and a '0'.
*
******************************************************************/
static int MemTestDevice(unsigned int memory_base, unsigned int nBytes)
{
  unsigned int offset;
  unsigned int pattern;
  unsigned int antipattern;
  unsigned int ret_code = 0x0;

  /* Fill memory with a known pattern. */
  for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4)
  {
    IOWR_32DIRECT(memory_base, offset, pattern);
  }

  printf(" .");

  /* Check each location and invert it for the second pass. */
  for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4)
  {
    if (IORD_32DIRECT(memory_base, offset) != pattern)
    {
      ret_code = (memory_base + offset);
      break;
    }
    antipattern = ~pattern;
    IOWR_32DIRECT(memory_base, offset, antipattern);
  }

  printf(" .");

  /* Check each location for the inverted pattern and zero it. */
  for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4)
  {
    antipattern = ~pattern;
    if (IORD_32DIRECT(memory_base, offset) != antipattern)
    {
      ret_code = (memory_base + offset);
      break;
    }
    IOWR_32DIRECT(memory_base, offset, 0x0);
  }
  return ret_code;
}

void happy_led()
{
	int i,j;
	for (i=0; i<8; i++)
	{
		IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0xffffffff);
		for (j=0; j<200000; j++) j++;
		IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0);
		for (j=0; j<200000; j++) j++;
	}
}

/******************************************************************
*  Function: TestRam
*
*  Purpose: Performs a full-test on the RAM specified.  The tests
*           run are:
*             - MemTestDataBus
*             - MemTestAddressBus
*             - MemTest8_16BitAccess
*             - MemTestDevice
*
******************************************************************/
static int test_ddr3()
{

  int memory_base, memory_end, memory_size;
  int ret_code = 0x0;

  /* Find out what range of memory we are testing */
  //MemGetAddressRange(&memory_base, &memory_end);

  memory_base = DDR3_IF_BASE;
  memory_end =  DDR3_IF_BASE + 0x8000;

  memory_size = (memory_end - memory_base);
  ret_code = MemTestDataBus(memory_base);

  if (ret_code)
  {
	  printf(" -Data bus test failed at bit 0x%X", (int)ret_code);
	  return ret_code;
  }
  else
	  printf(" -Data bus test passed\n");


    ret_code  = MemTestAddressBus(memory_base, memory_size);
    if  (ret_code)
    {
      printf(" -Address bus test failed at address 0x%X", (int)ret_code);
      return ret_code;
    }
    else
      printf(" -Address bus test passed\n");


  /* Test byte and half-word access. */
    ret_code = MemTest8_16BitAccess(memory_base);
    if  (ret_code)
    {
      printf(" -Byte and half-word access test failed at address 0x%X", (int)ret_code);
      return ret_code;
    }
    else
      printf(" -Byte and half-word access test passed\n");

  /* Test that each bit in the device can store both 1 and 0. */
    printf(" -Testing each bit in memory device.");
    ret_code = MemTestDevice(memory_base, memory_size);
    if  (ret_code)
    {
      printf("  failed at address 0x%X", (int)ret_code);
    }
    else
      printf("  passed\n");


  if (!ret_code)
  {
    printf("Memory at 0x%X Okay\n", memory_base);
    happy_led();
  }
}


void test_uart()
{
	int	uart;
	int result;
	char szHello[] = "Hello from Nios II!\r\n";
	char szRead[1];
	// open uart
	uart = open(USB_UART_NAME, O_ACCMODE); // UART_NAME defined in system.h
	if(!uart){
		printf("failed to open uart\n");
		return;
	}
	// write uart
	if (write(uart, szHello, strlen(szHello)) != strlen(szHello)){
		printf("failed to write uart");

	}
	close(uart);
	return;
}


void test_led()
{
	int i,j;
	for (i=0; i<15; i++)
	{
		IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, i);
		for (j=0; j<1000000; j++) j++;
	}
}






int main()
{

  printf("Hello from Nios II!\n");  //Test JTAG UART
  InitLcd();
  while (1)
  {
	 // IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, 0x00);
	 // 	usleep(700);
	 // IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, 0x01);
	 //   usleep(700);
	  //InitLcd();
	  test_lcd();
	 // usleep(2000000);
	  test_eth();
	  //test_led();		//Test LEDs
	 // test_uart();     	//Test USB UART (Please set BAUD RATE = 115200 on the host, user should see a "hello" message in the console.)
	 // test_ddr3();		//If the memory test passes, user should see all LEDs flashing quickly.
	  //test_sd_card(); //User can use the C library provided by Terasic to test the sd card interface. Due to the copyright issue, ignore it here.
  }
  return 0;
}
